package edu.kit.aifb.ruleintegrator.repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.semanticweb.yars.nx.Resource;
import org.yaml.snakeyaml.constructor.Construct;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.SequenceNode;
import org.yaml.snakeyaml.nodes.Tag;

public class RSConstructor extends SafeConstructor {
	
	public RSConstructor(){
		this.yamlConstructors.put(new Tag(RepositoryStatistics.class), new ConstructRS());
	}

	public class ConstructRS implements Construct{

		@Override
		public Object construct(Node node) {
			// 
            MappingNode mnode = (MappingNode) node;
            
            if(!mnode.getTag().equals(new Tag(RepositoryStatistics.class)))
            	return null;
            List<Resource> attributes=null;
            List<Resource> relations=null;
            List<Resource> classes=null;
            for(NodeTuple tpl:mnode.getValue()){
//				ScalarNode key=new ScalarNode(Tag.STR, "attributes", null, null, null);
            	if(((ScalarNode)tpl.getKeyNode()).getValue().equals("attributes")){
            		attributes=constructResources(tpl.getValueNode());
            	}
            	else if(((ScalarNode)tpl.getKeyNode()).getValue().equals("relations")){
            		relations=constructResources(tpl.getValueNode());            		
            	}else if(((ScalarNode)tpl.getKeyNode()).getValue().equals("classes")){
            		classes=constructResources(tpl.getValueNode());
            	}
            }
            Map<Resource,RelationStats> relStats=null;
            Map<Resource,ClassStats> clsStats=null;
            for(NodeTuple tpl:mnode.getValue()){
            	if(((ScalarNode)tpl.getKeyNode()).getValue().equals("relstats")){
            		relStats=constructRelationStats(tpl.getValueNode());
            	}else if(((ScalarNode)tpl.getKeyNode()).getValue().equals("clsstats")){
            		clsStats=constructClassStats(tpl.getValueNode());
            	}          	
            	
            }

			return new RepositoryStatistics(relations,attributes,classes,relStats,clsStats);
		}
		
		private Map<Resource, ClassStats> constructClassStats(Node valueNode) {
			Map<Resource,ClassStats> result=new HashMap<Resource,ClassStats>();
			MappingNode mnode=(MappingNode) valueNode;
			for(NodeTuple nt:mnode.getValue()){
				Resource cls=constructResource(nt.getKeyNode());
			
				ClassStats clsStats=constructClassStat(nt.getValueNode(),cls);
				result.put(cls, clsStats);
			}
			return result;
		}
		
		private ClassStats constructClassStat(Node node,Resource cls){
			MappingNode mnode=(MappingNode)node;
			List<Resource> sourceRelations=null;
			List<Resource> sourceAttributes=null;
			for(NodeTuple nt:mnode.getValue()){
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("sourcerelatoins")){
					sourceRelations=constructResources(nt.getValueNode());
				}
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("sourceattributes")){
					sourceAttributes=constructResources(nt.getValueNode());
				}
			}
			

			return new ClassStats(cls,sourceRelations, sourceAttributes);			
		}

		private Map<Resource, RelationStats> constructRelationStats(
				Node valueNode) {
			Map<Resource,RelationStats> result=new HashMap<Resource,RelationStats>();
			MappingNode mnode=(MappingNode) valueNode;
			for(NodeTuple nt:mnode.getValue()){
				Resource rel=constructResource(nt.getKeyNode());			
				RelationStats relStats=constructRelationStat(nt.getValueNode(),rel);
				result.put(rel, relStats);
			}
			return result;
		}

		private RelationStats constructRelationStat(Node node, Resource relationRes) {
			MappingNode mnode=(MappingNode)node;
			List<Resource> srcCls =null;
			List<Resource> tgtCls=null;
			List<Resource> srcRels=null;
			List<Resource> tgtRels=null;
			List<Resource> srcAtts=null;
			List<Resource> tgtAtts=null;
			for(NodeTuple nt:mnode.getValue()){
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("sourceclasses")){
					srcCls=constructResources(nt.getValueNode());
				}
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("targetclasses")){
					tgtCls=constructResources(nt.getValueNode());
				}
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("sourcerelations")){
					srcRels=constructResources(nt.getValueNode());
				}
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("targetrelations")){
					tgtRels=constructResources(nt.getValueNode());
				}
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("sourceattributes")){
					srcAtts=constructResources(nt.getValueNode());
				}
				if(((ScalarNode)nt.getKeyNode()).getValue().equals("targetattributes")){
					tgtAtts=constructResources(nt.getValueNode());
				}
			}
			

			return new RelationStats(relationRes, srcCls, tgtCls, srcRels, tgtRels, srcAtts, tgtAtts);			
		}

		@Override
		public void construct2ndStep(Node arg0, Object arg1) {
			// TODO Auto-generated method stub
			
		}
		
		private List<Resource> constructResources(Node node){
			List<Resource> result=new ArrayList<Resource>();
			SequenceNode snode=(SequenceNode)node;
			for(Node resNode:snode.getValue()){
				result.add(constructResource(resNode));
			}
			return result;
		}
		
		private Resource constructResource(Node node){
	        ScalarNode snode=(ScalarNode)node;
	        return new Resource(snode.getValue(),true);
		}
		
		private Resource findResource(List<Resource> list,String n3){
			Resource result=null;
			for(Resource res:list){
				if(res.toN3().equals(n3))
					result=res;
			}
			return result;
		}

			
	}
}
